﻿using System.Collections.Generic;
using AutoMapper;
using EnetaMvc.ApplicationServices.Dto;
using EnetaMvc.Core.Domain.Content;
using EnetaMvc.Core.Repositories;
using System;
using System.Linq;
using EnetaMvc.Infrastructure;
using EnetaMvc.Core.Domain.Common;
using EnetaMvc.Core.Domain.SLA;
using EnetaMvc.Core.Domain.News;

namespace EnetaMvc.ApplicationServices
{
    public class ContentService : IContentService
    {
        private readonly ICommentRepository _commentRepository;
        private readonly IContentItemRepository _contentItemRepository;
        private readonly IHtmlAreaRepository _htmlAreaRepository;
        private readonly ITagRepository _tagRepository;
        private readonly ITooltipRepository _tooltipRepository;
        private readonly IPublishStateRepository _publishStateRepository;
        private readonly IUserRepository _userRepository;
        private readonly ITagGroupRepository _tagGroupRepository;
        private readonly ISlaMonitoringLogRepository _slaMonitoringLogRepository;
        private readonly IBlogRepository _blogRepository;
        private readonly IDynamicMenuRepository _dynamicMenuRepository;
        private readonly IHtmlControlRepository _htmlControlRepository;

        public ContentService(ICommentRepository commentRepository,
                              IContentItemRepository contentItemRepository,
                              IHtmlAreaRepository htmlAreaRepository, 
                              ITagRepository tagRepository,
                              ITooltipRepository tooltipRepository,
                              IPublishStateRepository publishStateRepository,
                              IUserRepository userRepository,
                              ITagGroupRepository tagGroupRepository,
                              ISlaMonitoringLogRepository slaMonitoringLogRepository,
                              IBlogRepository blogRepository,
                              IDynamicMenuRepository dynamicMenuRepository,
                              IHtmlControlRepository htmlControlRepository)
        {
            _commentRepository = commentRepository;
            _contentItemRepository = contentItemRepository;
            _htmlAreaRepository = htmlAreaRepository;
            _tagRepository = tagRepository;
            _tooltipRepository = tooltipRepository;
            _publishStateRepository = publishStateRepository;
            _userRepository = userRepository;
            _tagGroupRepository = tagGroupRepository;
            _slaMonitoringLogRepository = slaMonitoringLogRepository;
            _blogRepository = blogRepository;
            _dynamicMenuRepository = dynamicMenuRepository;
            _htmlControlRepository = htmlControlRepository;
        }

        public HtmlAreaDto GetHtmlAreaByName(string name)
        {
            var htmlArea = _htmlAreaRepository.GetHtmlAreaByName(name);
            var htmlAreaDto = new HtmlAreaDto();

            Mapper.CreateMap<HtmlArea, HtmlAreaDto>();
            Mapper.Map(htmlArea, htmlAreaDto);

            return htmlAreaDto;
        }

        public TooltipDto GetTooltipByName(string name)
        {
            var tooltip = _tooltipRepository.GetTooltipByName(name);
            var tooltipDto = new TooltipDto();

            Mapper.CreateMap<Tooltip, TooltipDto>();
            Mapper.Map(tooltip, tooltipDto);

            return tooltipDto;
        }

        public IList<PublishStateDto> ListPublishStates()
        {
            var states = _publishStateRepository.ListPublishStates();
            var stateDtos = new List<PublishStateDto>();

            Mapper.CreateMap<PublishState, PublishStateDto>();
            Mapper.Map(states, stateDtos);

            return stateDtos;
        }

        public void SaveComment(CommentDto comment)
        {
            var commentToSave = new Comment();
            commentToSave.Body = comment.Body;
            commentToSave.Created = comment.Created;
            commentToSave.Author = _userRepository.GetUserById(comment.AuthorId);
            commentToSave.ContentItem = _contentItemRepository.GetContentItemById(comment.ContentItemId);

            _commentRepository.Save(commentToSave);
        }

        public bool IsUserContentOwner(string userToken, long contentItemId)
        {
            var user = _userRepository.GetUserByLiveIdToken(userToken);
            if (user == null)
                return false;

            var contentItem = _contentItemRepository.GetContentItemById(contentItemId);
            if (contentItem == null)
                return false;

            return (contentItem.CreatedBy.Id == user.Id);
        }


        public IList<TagDto> ListTags()
        {
            var tagList = _tagRepository.ListTags();
            var tagDtos = new List<TagDto>();

            tagDtos = (from tag in tagList
                       select new TagDto()
                       {
                           Id = tag.Id,
                           Name = tag.Name,
                           GroupId = tag.Group.Id.ToString(),
                           GroupName = tag.Group.Name
                       }).ToList();

            return tagDtos;
        }


        public IList<TagGroupDto> ListTagGroups()
        {
            IList<TagGroup> tagGroupList = _tagGroupRepository.ListTagGroups();
            IList<TagGroupDto> tagGroupDtos = new List<TagGroupDto>();

            Mapper.CreateMap<TagGroup, TagGroupDto>();
            Mapper.Map(tagGroupList, tagGroupDtos);

            return tagGroupDtos;
        }

        public void SaveTagGroup(TagGroupDto tagGroupDto)
        {
            TagGroup tagGroup = new TagGroup();
            
            Mapper.CreateMap<TagGroupDto, TagGroup>();
            Mapper.Map(tagGroupDto, tagGroup);

            _tagGroupRepository.SaveTagGroup(tagGroup);
        }

        public void DeleteTagGroup(long tagGroupId)
        {
            //cascade delete tags for this tagGroup
            var tags = _tagRepository.ListTagsByGroupId(tagGroupId);
            foreach (var tag in tags)
                _tagRepository.DeleteTag(tag.Id);
            _tagGroupRepository.DeleteTagGroup(tagGroupId);
        }


        public bool HasTags(long tagGroupId)
        {
            return _tagGroupRepository.HasTags(tagGroupId);
        }


        public void SaveTag(TagDto tagDto)
        {
            Tag tag = new Tag();

            tag.Group = new TagGroup();
            tag.Id = tagDto.Id;
            tag.Name = tagDto.Name;
            tag.Group.Id = Convert.ToInt64(tagDto.GroupId);
            tag.Group.Name = tagDto.GroupName;

            _tagRepository.SaveTag(tag);
        }

        public void DeleteTag(long id)
        {
            //cascade delete content_item_tags for tagId
            _contentItemRepository.DeleteContentItemsByTagId(id);
            _tagRepository.DeleteTag(id);
        }


        public bool IsTagUsed(long id)
        {
            int contentsCount = _contentItemRepository.ListContentItemsByTagId<ContentItem>(id).Count;
            return (contentsCount > 0);
        }


        public PagedResult<SlaMonitoringLogDto> ListSlaMonitoringLogs(int page, int pageSize)
        {
            var slaLogs = _slaMonitoringLogRepository.ListSlaLogs<SlaMonitoringLog>(page, pageSize);
            return GetSlaMonitoringDtoList(slaLogs);
        }

        public void SaveBlogSlaitoringLog(long blogId, long newPublishStateId, long userId)
        {
            Blog originalBlog = _blogRepository.GetBlogById(blogId);
            if (originalBlog == null) 
                return;

            BlogSlaLog slaLog = new BlogSlaLog();
            slaLog.Blog = originalBlog;
            slaLog.NewPublishState = new PublishState() { Id=newPublishStateId};
            slaLog.User = new User() { Id=userId};
            slaLog.PreviousPublishState = new PublishState() { Id=originalBlog.PublishingState.Id};
            slaLog.PreviousPublishStateUser = new User() { Id = originalBlog.PublishingStateBy.Id };

            slaLog.NewStateDate = DateTime.Now;
            slaLog.PreviousStateDate = originalBlog.PublishingStateDate;

            _slaMonitoringLogRepository.SaveSlaLog(slaLog);
        }


        public void SaveContentItemSlagLog(long contentItemId, long newPublishStateId, long userId)
        {
            ContentItem originalContentItem = _contentItemRepository.GetContentItemById(contentItemId);
            if (originalContentItem == null)
                return;

            ContentItemSlaLog slaLog = new ContentItemSlaLog();
            slaLog.ContentItem = originalContentItem;
            slaLog.NewPublishState = new PublishState() { Id = newPublishStateId };
            slaLog.User = new User() { Id = userId };
            slaLog.PreviousPublishState = new PublishState() { Id = originalContentItem.PublishState.Id };
            slaLog.PreviousPublishStateUser = new User() { Id = originalContentItem.PublishStateBy.Id };

            slaLog.NewStateDate = DateTime.Now;
            slaLog.PreviousStateDate = originalContentItem.PublishStateDate;

            _slaMonitoringLogRepository.SaveSlaLog(slaLog);
        }


        public IList<DynamicMenuDto> ListDynamicMenus()
        {
            IEnumerable<DynamicMenu> rootMenus = _dynamicMenuRepository.GetAllRootMenus();
            IList<DynamicMenuDto> rootMenuDtos = new List<DynamicMenuDto>();
            Mapper.CreateMap<DynamicMenu, DynamicMenuDto>()
                .ForMember(x => x.Children, op => op.Ignore());

            //Bojan: We go only one level of submenu items
            foreach (DynamicMenu item in rootMenus.OrderBy(x => x.OrderPosition))
            {
                DynamicMenuDto itemDto = new DynamicMenuDto();
                Mapper.Map(item, itemDto);
                foreach (DynamicMenu subitem in item.Children.OrderBy(x => x.OrderPosition))
                {
                    DynamicMenuDto subitemDto = new DynamicMenuDto();
                    Mapper.Map(subitem, subitemDto);
                    itemDto.Children.Add(subitemDto);
                }
                rootMenuDtos.Add(itemDto);
            }

            return rootMenuDtos;
        }


        public void SaveDynamicMenu(DynamicMenuDto dynamicMenuDto)
        {
            DynamicMenu menuItem = (dynamicMenuDto.Id == 0
                                        ? new DynamicMenu()
                                        : _dynamicMenuRepository.GetMenuById(dynamicMenuDto.Id));

            Mapper.CreateMap<DynamicMenuDto, DynamicMenu>()
                .ForMember(x => x.Children, op => op.Ignore());
            Mapper.Map(dynamicMenuDto, menuItem);

            _dynamicMenuRepository.SaveMenu(menuItem);
        }

        public void DeleteDynamicMenu(long id)
        {
            _dynamicMenuRepository.DeleteMenu(id);
        }

        public DynamicMenuDto GetDynamicMenu(long id)
        {
            DynamicMenu menuItem = _dynamicMenuRepository.GetMenuById(id);
            Mapper.CreateMap<DynamicMenu, DynamicMenuDto>();
            return Mapper.Map<DynamicMenuDto>(menuItem);
        }


        public IList<HtmlControlDto> ListHtmlControls()
        {
            Mapper.CreateMap<HtmlControl, HtmlControlDto>();
            IList<HtmlControl> htmlControls = _htmlControlRepository.ListHtmlControls();
            return Mapper.Map<IList<HtmlControlDto>>(htmlControls);
        }

        public IList<HtmlControlDto> ListVisibleHtmlControls()
        {
            Mapper.CreateMap<HtmlControl, HtmlControlDto>();
            IList<HtmlControl> htmlControls = _htmlControlRepository.ListHtmlControls()
                    .Where(x => x.Visible == true)
                    .OrderBy(x => x.OrderPosition).ToList();
            return Mapper.Map<IList<HtmlControlDto>>(htmlControls);
        }

        public void SaveHtmlControl(HtmlControlDto htmlControl)
        {
            Mapper.CreateMap<HtmlControlDto, HtmlControl>();
            HtmlControl htmlControlEntity = (htmlControl.Id == 0
                ? new HtmlControl()
                : _htmlControlRepository.GetHtmlControlById(htmlControl.Id));

            Mapper.Map(htmlControl, htmlControlEntity);
            _htmlControlRepository.SaveHtmlControl(htmlControlEntity);
        }

        public void DeleteHtmlControl(long id)
        {
            _htmlControlRepository.DeleteHtmlControl(id);
        }

        public HtmlControlDto GetHtmlControl(long id)
        {
            Mapper.CreateMap<HtmlControl, HtmlControlDto>();
            HtmlControl htmlControl = _htmlControlRepository.GetHtmlControlById(id);
            return Mapper.Map<HtmlControlDto>(htmlControl);
        }

       


        //*******************PRIVATE METHODS*******************

        private static PagedResult<SlaMonitoringLogDto> GetSlaMonitoringDtoList<T>(PagedResult<T> slaLogs)
            where T : SlaMonitoringLog
        {
            var slaLogsDtos = new List<SlaMonitoringLogDto>();
            var dtoResult = new PagedResult<SlaMonitoringLogDto>();

            Mapper.CreateMap<SlaMonitoringLog, SlaMonitoringLogDto>()
                .ForMember(x => x.NewPublishState, x => x.MapFrom(z => z.NewPublishState.Name))
                .ForMember(x => x.PreviousPublishState, x => x.MapFrom(z => z.PreviousPublishState.Name))
                .ForMember(x => x.PreviousPublishStateUser, x => x.MapFrom(z => z.PreviousPublishStateUser.UserName))
                .ForMember(x => x.User, x => x.MapFrom(z => z.User.UserName));
            Mapper.Map(slaLogs.Results, slaLogsDtos);

            Mapper.CreateMap(slaLogs.GetType(), dtoResult.GetType())
                  .ForMember("Results", m => m.Ignore());
            Mapper.Map(slaLogs, dtoResult);

            dtoResult.Results = slaLogsDtos;
            return dtoResult;
        }






        
    }
}